﻿namespace NetFx.MSIL
{
  using System;
  using System.Text;

  using System.Reflection;
  using System.Reflection.Emit;
  using System.Runtime.InteropServices;
  using System.Diagnostics;
  using System.Diagnostics.CodeAnalysis;
  using System.Diagnostics.SymbolStore;

  public enum PrimitiveType
  {
    natural_int,
    natural_uint,
    natural_float,
    int8,
    int16,
    int32,
    int64,
    uint8,
    uint16,
    uint32,
    uint64,
    float32,
    float64,
    reference,
    pointer
  }

  [Flags]
  public enum BinaryOperation
  {
    None = 0x00000000,
    Add  = 0x00000001,
    Sub  = 0x00000002,
    Mul  = 0x00000003,
    Div  = 0x00000004,
    Rem  = 0x00000005,

    And  = 0x00000006,
    Or   = 0x00000007,
    Not  = 0x00000008,
    Xor  = 0x00000009,
    Neg  = 0x0000000A,
    Shl  = 0x0000000B,
    Shr  = 0x0000000C,
  }

  [Flags]
  public enum BranchCondition
  {
    None          = 0x00000000,
    Equal         = 0x00000001,
    Null          = 0x00000001,
    GrThan        = 0x00000002,
    LsThan        = 0x00000004,
    GeThan        = 0x00000003,
    LeThan        = 0x00000005,
    Differ        = 0x00000006,
    NotNull       = 0x00000006,
    Always        = 0x00000007,
    False         = 0x00000008,
    True          = 0x00000009,
    SwitchCase    = 0x0000000A,
  }

  /// <summary>
  /// 逻辑生成器。
  /// </summary>
  public class LogicGenerator:AnyGenerator
  {
    #region Statics
    public static LogicGenerator of(MethodBase builder)
    {
      return new LogicGenerator(builder);
    }
    #endregion
    #region Fields
    protected MethodBase builder;
    protected ILGenerator generator;
    protected bool checking = false;
    protected bool shortFormat = false;
    protected bool topSigned = true;
    protected CallingConvention  interopConvertion;
    protected CallingConventions managedConvertion;
    protected Type[] reqParameterTypes = null;
    protected Type[] optParameterTypes = null;
    #endregion
    #region Properties
    public override object AnyBuilder
    {
      get { return this.builder; }
    }
    public override DefType GeneratorType
    {
      get
      {
        return DefType.Logic;
      }
    }
    public virtual ILGenerator Generator
    {
      get
      {
        if (this.generator == null)
        {
          if (this.MethodBuilder!=null)
          {
            this.generator = this.MethodBuilder.GetILGenerator();
          }
          else if (this.ConstructorBuilder!=null)
          {
            this.generator = this.ConstructorBuilder.GetILGenerator();
          }
        }
        return this.generator;
      }
    }
    public virtual MethodBuilder MethodBuilder
    {
      get
      {
        return this.builder as MethodBuilder;
      }
    }
    public virtual ConstructorBuilder ConstructorBuilder
    {
      get
      {
        return this.builder as ConstructorBuilder;
      }
    }
    public virtual ParameterInfo[] Parameters
    {
      get
      {
        return ((MethodBase)this.builder).GetParameters();
      }
    }

    protected virtual bool Checking
    {
      get
      {
        return this.checking;
      }
    }
    protected virtual bool TopUnsigned
    {
      get
      {
        return this.topSigned;
      }
    }
    protected virtual bool ShortFormat
    {
      get
      {
        return this.shortFormat;
      }
    }
    protected virtual CallingConvention InteropConvertion
    {
      get
      {
        return this.interopConvertion;
      }
    }
    protected virtual CallingConventions ManagedConvertion
    {
      get
      {
        return this.managedConvertion;
      }
    }
    protected virtual Type[] ReqParameterTypes
    {
      get
      {
        return this.reqParameterTypes;
      }

    }
    protected virtual Type[] OptParameterTypes
    {
      get
      {
        return this.optParameterTypes;
      }
    }
    #endregion
    #region Constructors
    public LogicGenerator(MethodBase builder)
    {
      if (builder == null) throw new ArgumentNullException("builder can not be null!");
      this.builder = builder;
    }
    #endregion
    #region Methods
    #region Convetion
    public virtual void BoxAs(Type destType)
    {
      if (destType == null) destType = typeof(object);

      OpCode code = OpCodes.Box;
      this.Generator.Emit(code, destType);
    }
    public virtual void UnboxAs(Type destType)
    {
      if (destType == null) throw new ArgumentException("orgType can not be null!");

      OpCode code = OpCodes.Unbox;
      this.Generator.Emit(code, destType);
    }
    public virtual void CastAs(Type destType)
    {
      if (destType == null) throw new ArgumentException("destType can not be null!");

      OpCode code = OpCodes.Castclass;
      this.Generator.Emit(code, destType);
    }
    public virtual void ConvertTo(PrimitiveType primitiveType)
    {
      this.ConvertTo(primitiveType, this.topSigned);
    }
    public virtual void ConvertTo(PrimitiveType primitiveType, bool topSigned)
    {
      this.ConvertTo(primitiveType, topSigned, this.checking);
    }
    public virtual void ConvertTo(PrimitiveType primitiveType, bool topSigned, bool check)
    {
      OpCode code = OpCodes.Conv_I;

      switch (primitiveType)
      {
        case PrimitiveType.natural_int:
          code = topSigned 
            ? (check ? OpCodes.Conv_Ovf_I : OpCodes.Conv_I)
            : (OpCodes.Conv_Ovf_I_Un);
          break;
        case PrimitiveType.int8:
          code = topSigned
            ? (check ? OpCodes.Conv_Ovf_I1 : OpCodes.Conv_I1)
            : (OpCodes.Conv_Ovf_I1_Un) 
            ;
          break;
        case PrimitiveType.int16:
          code = topSigned
            ? (check ? OpCodes.Conv_Ovf_I2 : OpCodes.Conv_I2)
            : (OpCodes.Conv_Ovf_I2_Un)
            ;
          break;
        case PrimitiveType.int32:
          code = topSigned
            ? (check ? OpCodes.Conv_Ovf_I4 : OpCodes.Conv_I4) 
            : (OpCodes.Conv_Ovf_I4_Un)
            ;
          break;
        case PrimitiveType.int64:
          code = topSigned
            ? (check ? OpCodes.Conv_Ovf_I8 : OpCodes.Conv_I8)
            : (OpCodes.Conv_Ovf_I8_Un)
            ;
          break;
        case PrimitiveType.natural_uint:
          code = check ? OpCodes.Conv_Ovf_U : OpCodes.Conv_U;
          break;
        case PrimitiveType.uint8:
          code = check ? OpCodes.Conv_Ovf_U1 : OpCodes.Conv_U1;
          break;
        case PrimitiveType.uint16:
          code = check ? OpCodes.Conv_Ovf_U2 : OpCodes.Conv_U2;
          break;
        case PrimitiveType.uint32:
          code = check ? OpCodes.Conv_Ovf_U4 : OpCodes.Conv_U4;
          break;
        case PrimitiveType.uint64:
          code = check ? OpCodes.Conv_Ovf_U8 : OpCodes.Conv_U8;
          break;
        case PrimitiveType.float32:
          code = topSigned
            ? (OpCodes.Conv_R4)
            : (OpCodes.Conv_R_Un)
            ;
          break;
        case PrimitiveType.float64:
          code = OpCodes.Conv_R8;
          break;
        default:
          throw new NotSupportedException("The instruction with operand type of " + primitiveType + " is invalid!");
      }

      this.Generator.Emit(code);
    }
    #endregion
    #region Load const
    public virtual void LoadConst(byte c)
    {
      this.Generator.Emit(OpCodes.Ldc_I4_S, c);
    }
    public virtual void LoadConst(int c)
    {
      OpCode code = this.CreateNopCode();

      if (c >= -1 && c <= 8)
      {
        switch (c)
        {
          case -1:
            code = OpCodes.Ldc_I4_M1;
            break;
          case 0:
            code = OpCodes.Ldc_I4_0;
            break;
          case 1:
            code = OpCodes.Ldc_I4_1;
            break;
          case 2:
            code = OpCodes.Ldc_I4_2;
            break;
          case 3:
            code = OpCodes.Ldc_I4_3;
            break;
          case 4:
            code = OpCodes.Ldc_I4_4;
            break;
          case 5:
            code = OpCodes.Ldc_I4_5;
            break;
          case 6:
            code = OpCodes.Ldc_I4_6;
            break;
          case 7:
            code = OpCodes.Ldc_I4_7;
            break;
          case 8:
            code = OpCodes.Ldc_I4_8;
            break;
        }
        this.Generator.Emit(code);
      }
      else
      {
        if (c >= -128 && c <= 127)
        {
          code = OpCodes.Ldc_I4_S;
          this.Generator.Emit(code, (byte)c);
        }
        else
        {
          code = OpCodes.Ldc_I4;
          this.Generator.Emit(code, c);
        }
      }
    }
    public virtual void LoadConst(long c)
    {
      this.Generator.Emit(OpCodes.Ldc_I8, c);
    }
    public virtual void LoadConst(float c)
    {
      this.Generator.Emit(OpCodes.Ldc_R4, c);
    }
    public virtual void LoadConst(double c)
    {
      this.Generator.Emit(OpCodes.Ldc_R8, c);
    }
    public virtual void LoadConst(ValueType c)
    {
      if (c is int|| c is uint)
      {
        LoadConst((int)c);
      }
      else if (c is byte || c is sbyte)
      {
        LoadConst((byte)c);
      }
      else if (c is short || c is ushort)
      {
        LoadConst((short)c);
      }
      else if (c is long || c is ulong)
      {
        LoadConst((long)c);
      }
      else if (c is float)
      {
        LoadConst((float)c);
      }
      else if (c is double)
      {
        LoadConst((double)c);
      }
      else
      {
        throw new ArgumentException("c is not primitive type, can not use LoadConst");
      }
    }
    #endregion
    #region Array operations
    #region LoadElement
    public virtual void LoadElementRef()
    {
      OpCode code = OpCodes.Ldelem_Ref;
      this.Generator.Emit(code);
    }
    public virtual void LoadElementAddress(Type elementType)
    {
      if (elementType == null) throw new ArgumentNullException("elementType can not be null!");
      OpCode code = OpCodes.Ldelema;
      this.Generator.Emit(code, elementType);
    }
    public virtual void LoadElement(PrimitiveType elementType)
    {
      OpCode code = this.CreateNopCode();

      switch (elementType)
      {
        case PrimitiveType.natural_int:
          code = OpCodes.Ldelem_I;
          break;
        case PrimitiveType.int8:
          code = OpCodes.Ldelem_I1;
          break;
        case PrimitiveType.int16:
          code = OpCodes.Ldelem_I2;
          break;
        case PrimitiveType.int32:
          code = OpCodes.Ldelem_I4;
          break;
        case PrimitiveType.int64:
          code = OpCodes.Ldelem_I8;
          break;
        case PrimitiveType.float32:
          code = OpCodes.Ldelem_R4;
          break;
        case PrimitiveType.float64:
          code = OpCodes.Ldelem_R8;
          break;
        case PrimitiveType.uint8:
          code = OpCodes.Ldelem_U1;
          break;
        case PrimitiveType.uint16:
          code = OpCodes.Ldelem_U2;
          break;
        case PrimitiveType.uint32:
          code = OpCodes.Ldelem_U4;
          break;
        default:
          throw new NotSupportedException("The instruction with operand type of " + elementType + " is invalid!");
      }

      this.Generator.Emit(code);
    }
    #endregion
    #region StoreElement
    public virtual void StoreElementRef()
    {
      OpCode code = OpCodes.Stelem_Ref;
      this.Generator.Emit(code);
    }
    public virtual void StoreElement(PrimitiveType elementType)
    {
      OpCode code = this.CreateNopCode();
      switch (elementType)
      {
        case PrimitiveType.natural_int:
          code = OpCodes.Stelem_I;
          break;
        case PrimitiveType.int8:
          code = OpCodes.Stelem_I1;
          break;
        case PrimitiveType.int16:
          code = OpCodes.Stelem_I2;
          break;
        case PrimitiveType.int32:
          code = OpCodes.Stelem_I4;
          break;
        case PrimitiveType.int64:
          code = OpCodes.Stelem_I8;
          break;
        case PrimitiveType.float32:
          code = OpCodes.Ldelem_R4;
          break;
        case PrimitiveType.float64:
          code = OpCodes.Stelem_R8;
          break;
        default:
          throw new NotSupportedException("The instruction with operand type of " + elementType + " is invalid!");
      }
      this.Generator.Emit(code);

    }
    #endregion
    #region Utils
    public virtual void GetArrayLength()
    {
      OpCode code = OpCodes.Ldlen;
      this.Generator.Emit(code);
    }
    #endregion
    #endregion
    #region Local variables
    #region StoreAt
    public virtual void StoreAt(byte index)
    {
      OpCode code = OpCodes.Stloc_S;

      this.Generator.Emit(code, index);
    }
    public virtual void StoreAt(ushort index)
    {
      OpCode code = this.CreateNopCode();

      if (index <= 3)
      {
        switch (index)
        {
          case 0:
            code = OpCodes.Stloc_0;
            break;
          case 1:
            code = OpCodes.Stloc_1;
            break;
          case 2:
            code = OpCodes.Stloc_2;
            break;
          case 3:
            code = OpCodes.Stloc_3;
            break;
        }
        this.Generator.Emit(code);
      }
      else
      {
        code = OpCodes.Stloc;
        this.Generator.Emit(code, index);
      }
    }
    public virtual void StoreAt(LocalBuilder local)
    {
      this.StoreAt(local, this.ShortFormat);
    }
    public virtual void StoreAt(LocalBuilder local, bool shortFormat)
    {
      OpCode code = (shortFormat) ? OpCodes.Stloc_S : OpCodes.Stloc;
      this.Generator.Emit(code, local);
    }
    #endregion
    #region LoadAt
    public virtual void LoadAddressAt(byte index)
    {
      OpCode code = OpCodes.Ldloca_S;
      this.Generator.Emit(code, index);
    }
    public virtual void LoadAddressAt(ushort index)
    {
      OpCode code = OpCodes.Ldloca;
      this.Generator.Emit(code, index);
    }
    public virtual void LoadAddressAt(LocalBuilder local)
    {
      this.LoadAddressAt(local, this.ShortFormat);
    }
    public virtual void LoadAddressAt(LocalBuilder local,bool shortFormat)
    {
      OpCode code = (shortFormat) ? OpCodes.Ldloca_S : OpCodes.Ldloca;
      this.Generator.Emit(code, local);
    }
    public virtual void LoadAt(byte index)
    {
      OpCode code = OpCodes.Ldloc_S;

      this.Generator.Emit(code, index);

    }
    public virtual void LoadAt(ushort index)
    {
      OpCode code = this.CreateNopCode();

      if (index <= 3)
      {
        switch (index)
        {
          case 0:
            code = OpCodes.Ldloc_0;
            break;
          case 1:
            code = OpCodes.Ldloc_1;
            break;
          case 2:
            code = OpCodes.Ldloc_2;
            break;
          case 3:
            code = OpCodes.Ldloc_3;
            break;
        }
        this.Generator.Emit(code);
      }
      else
      {
        code = OpCodes.Ldloc;
        this.Generator.Emit(code, index);
      }

    }
    public virtual void LoadAt(LocalBuilder local)
    {
      this.LoadAt(local, this.ShortFormat);
    }
    public virtual void LoadAt(LocalBuilder local, bool shortFormat)
    {
      OpCode code = (shortFormat) ? OpCodes.Ldloc_S : OpCodes.Ldloc;
      this.Generator.Emit(code, local);
    }
    #endregion
    #endregion
    #region Controls
    public virtual void Branch(Label destination, BranchCondition condition)
    {
      this.Branch(destination, condition, this.TopUnsigned);
    }
    public virtual void Branch(Label destination, BranchCondition condition, bool asUnsigned)
    {
      this.Branch(destination, condition, asUnsigned, this.ShortFormat);
    }
    public virtual void Branch(Label destination, BranchCondition condition, bool asUnsigned, bool shortFormat)
    {
      OpCode code = this.CreateNopCode();

      if (shortFormat)
      {
        switch (condition)
        {
          case BranchCondition.Equal:
            code = OpCodes.Beq_S;
            break;
          case BranchCondition.GrThan:
            code = (asUnsigned) ? OpCodes.Bgt_Un_S : OpCodes.Bgt_S;
            break;
          case BranchCondition.LsThan:
            code = (asUnsigned) ? OpCodes.Blt_Un_S : OpCodes.Blt_S;
            break;
          case BranchCondition.GeThan:
            code = (asUnsigned) ? OpCodes.Bge_Un_S : OpCodes.Bge_S;
            break;
          case BranchCondition.LeThan:
            code = (asUnsigned) ? OpCodes.Ble_Un_S : OpCodes.Ble_S;
            break;
          case BranchCondition.Differ:
            code = OpCodes.Bne_Un_S;
            break;
          case BranchCondition.Always:
            code = OpCodes.Br_S;
            break;
          case BranchCondition.True:
            code = OpCodes.Brtrue_S;
            break;
          case BranchCondition.False:
            code = OpCodes.Brfalse_S;
            break;
          default:
            throw new ArgumentException("conditon is not acceptable!");
            
        }
      }
      else
      {
        switch (condition)
        {
          case BranchCondition.Equal:
            code = OpCodes.Beq;
            break;
          case BranchCondition.GrThan:
            code = (asUnsigned) ? OpCodes.Bgt_Un : OpCodes.Bgt;
            break;
          case BranchCondition.LsThan:
            code = (asUnsigned) ? OpCodes.Blt_Un : OpCodes.Blt;
            break;
          case BranchCondition.GeThan:
            code = (asUnsigned) ? OpCodes.Bge_Un : OpCodes.Bge;
            break;
          case BranchCondition.LeThan:
            code = (asUnsigned) ? OpCodes.Ble_Un : OpCodes.Ble;
            break;
          case BranchCondition.Differ:
            code = OpCodes.Bne_Un;
            break;
          case BranchCondition.Always:
            code = OpCodes.Br;
            break;
          case BranchCondition.True:
            code = OpCodes.Brtrue;
            break;
          case BranchCondition.False:
            code = OpCodes.Brfalse;
            break;
          default:
            break;
        }
      }
      this.Generator.Emit(code, destination);
    }
    public virtual void Branch(MethodInfo destmethod)
    {
      if (destmethod == null) throw new ArgumentNullException("destmethod can not be null!");
      OpCode code = OpCodes.Jmp;
      this.Generator.Emit(code, destmethod);
    }
    public virtual void Breakpoint()
    {
      OpCode code = OpCodes.Break;
      this.Generator.Emit(code);
    }
    public virtual void Return()
    {
      OpCode code = OpCodes.Ret;
      this.Generator.Emit(code);
    }
    public virtual void Branches(params Label[] labels)
    {
      if (labels == null) throw new ArgumentNullException("labels can not be null!");
      OpCode code = OpCodes.Switch;
      this.Generator.Emit(code, labels);
    }
    public virtual void Invoke(ConstructorInfo constructorInfo)
    {
      this.Generator.Emit(OpCodes.Call, constructorInfo);
    }
    public virtual void VirtualInvoke(ConstructorInfo constructorInfo)
    {
      this.Generator.Emit(OpCodes.Callvirt, constructorInfo);
    }
    public virtual void Invoke(MethodInfo methodInfo)
    {
      this.Invoke(methodInfo, this.OptParameterTypes);
      this.OptParametersRestore();
    }
    public virtual void Invoke(MethodInfo methodInfo, params Type[] opt_parameterTypes)
    {
      this.Generator.EmitCall(OpCodes.Call, methodInfo, opt_parameterTypes);
    }
    public virtual void VirtualInvoke(MethodInfo methodInfo)
    {
      this.VirtualInvoke(methodInfo, this.OptParameterTypes);
      this.OptParametersRestore();
    }
    public virtual void VirtualInvoke(MethodInfo methodInfo, params Type[] opt_parameterTypes)
    {
      this.Generator.EmitCall(OpCodes.Callvirt, methodInfo, opt_parameterTypes);
    }
    public virtual void InteropInvoke(Type returnType)
    {
      if (this.OptParameterTypes == null)
      {
        this.InteropInvoke(returnType, this.OptParameterTypes);
      }
      else
      {
        this.InteropInvoke(returnType, this.ReqParameterTypes, this.OptParameterTypes);
      }
      this.OptParametersRestore();
      this.ReqParametersRestore();
    }
    public virtual void InteropInvoke(Type returnType, Type[] parameterTypes)
    {
      if (parameterTypes == null) throw new ArgumentNullException("parameterTypes can not be null!");
      this.InteropInvoke(this.InteropConvertion, returnType, parameterTypes);
      this.InteropConvertionRestore();
    }
    public virtual void InteropInvoke(Type returnType, Type[] parameterTypes, params Type[] optParameterTypes)
    {
      if (parameterTypes == null) throw new ArgumentNullException("parameterTypes can not be null!");
      this.InteropInvoke(this.ManagedConvertion, returnType, parameterTypes, optParameterTypes);
      this.ManagedConvertionRestore();
    }
    public virtual void InteropInvoke(CallingConvention convertions, Type returnType, Type[] parameterTypes)
    {
      this.Generator.EmitCalli(OpCodes.Calli, convertions, returnType, parameterTypes);
    }
    public virtual void InteropInvoke(CallingConventions convertions, Type returnType, Type[] parameterTypes, params Type[] optParameterTypes)
    {
      this.Generator.EmitCalli(OpCodes.Calli, convertions, returnType, parameterTypes, optParameterTypes);
    }
    #endregion
    #region Comparation and checking
    public virtual void TestEquality()
    {
      OpCode code = OpCodes.Ceq;
      this.Generator.Emit(code);
    }
    public virtual void TestGreaterThan()
    {
      this.TestGreaterThan(this.TopUnsigned);
    }
    public virtual void TestGreaterThan(bool asUnsigned)
    {
      OpCode code = asUnsigned ? OpCodes.Cgt_Un : OpCodes.Cgt;
      this.Generator.Emit(code);
    }
    public virtual void TestLessThan()
    {
      this.TestLessThan(this.TopUnsigned);
    }
    public virtual void TestLessThan(bool asUnsigned)
    {
      OpCode code = asUnsigned ? OpCodes.Clt_Un : OpCodes.Clt;
      this.Generator.Emit(code);
    }
    public virtual void TestInstanceOf(Type destType)
    {
      if (destType == null) throw new ArgumentException("destType can not be null!");

      OpCode code = OpCodes.Isinst;
      this.Generator.Emit(code, destType);
    }
    public virtual void GetSizeOf(Type destType)
    {
      if (destType == null) throw new ArgumentException("destType can not be null!");

      OpCode code = OpCodes.Sizeof;
      this.Generator.Emit(code, destType);
    }
    public virtual void CheckInfinity()
    {
      OpCode code = OpCodes.Ckfinite;
      this.Generator.Emit(code);

    }
    #endregion
    #region Arguments
    public virtual void GetArgList()
    {
      OpCode code = OpCodes.Arglist;
      this.Generator.Emit(code);
    }
    public virtual void StoreArgumentAt(byte index)
    {
      OpCode code = OpCodes.Starg_S;
      this.Generator.Emit(code, index);
    }
    public virtual void StoreArgumentAt(ushort index)
    {
      if (index >= 0 && index <= 255)
      {
        StoreArgumentAt((byte)index);
      }
      else
      {
        OpCode code = OpCodes.Starg;
        this.Generator.Emit(code, index);
      }
    }
    public virtual void LoadArgumentAt(byte index)
    {
      OpCode code = OpCodes.Ldarg_S;
      this.Generator.Emit(code,index);
    }
    public virtual void LoadArgumentAt(ushort index)
    {
      OpCode code = OpCodes.Ldarg;
      if (index <= 3)
      {
        switch (index)
        {
          case 0:
            code = OpCodes.Ldarg_0;
            break;
          case 1:
            code = OpCodes.Ldarg_1;
            break;
          case 2:
            code = OpCodes.Ldarg_2;
            break;
          case 3:
            code = OpCodes.Ldarg_3;
            break;
          default:
            break;
        }
        this.Generator.Emit(code);
      }
      else
      {
        if (index >= 0 && index <= 255)
        {
          this.LoadArgumentAt((byte)index);
        }
        else
        {
          this.Generator.Emit(code, index);
        }
      }
    }
    public virtual void LoadArgumentAddressAt(byte index)
    {
      OpCode code = OpCodes.Ldarga_S;
      this.Generator.Emit(code);
    }
    public virtual void LoadArgumentAddressAt(ushort index)
    {
      OpCode code = OpCodes.Ldarga;
      this.Generator.Emit(code,index);
    }
    #endregion
    #region Binary Operations
    public virtual void Execute(BinaryOperation op)
    {
      this.Execute(op, this.TopUnsigned);
    }
    public virtual void Execute(BinaryOperation op, bool asUnsigned)
    {
      this.Execute(op, asUnsigned, this.Checking);
    }
    public virtual void Execute(BinaryOperation op, bool asUnsigned, bool checking)
    {
      OpCode code = this.CreateNopCode();
      switch (op)
      {
        case BinaryOperation.Add:
          if (checking)
          {
            code = (asUnsigned) ? OpCodes.Add_Ovf_Un : OpCodes.Add_Ovf;
          }
          else
          {
            code = OpCodes.Add;
          }
          break;
        case BinaryOperation.Sub:
          if (checking)
          {
            code = (asUnsigned) ? OpCodes.Sub_Ovf_Un : OpCodes.Sub_Ovf;
          }
          else
          {
            code = OpCodes.Sub;
          }
          break;
        case BinaryOperation.Mul:
          if (checking)
          {
            code = (asUnsigned) ? OpCodes.Mul_Ovf_Un : OpCodes.Mul_Ovf;
          }
          else
          {
            code = OpCodes.Mul;
          }
          break;
        case BinaryOperation.Div:
          code = (asUnsigned) ? OpCodes.Div_Un : OpCodes.Div;
          break;
        case BinaryOperation.Rem:
          code = (asUnsigned) ? OpCodes.Rem_Un : OpCodes.Rem;
          break;
        case BinaryOperation.And:
          code = OpCodes.And;
          break;
        case BinaryOperation.Or:
          code = OpCodes.Or;
          break;
        case BinaryOperation.Not:
          code = OpCodes.Not;
          break;
        case BinaryOperation.Xor:
          code = OpCodes.Xor;
          break;
        case BinaryOperation.Neg:
          code = OpCodes.Neg;
          break;
        case BinaryOperation.Shl:
          code = OpCodes.Shl;
          break;
        case BinaryOperation.Shr:
          code = (asUnsigned) ? OpCodes.Shr_Un : OpCodes.Shr;
          break;
        default:
          break;
      }
    }
    #endregion
    #region Working with memory
    public virtual void StoreIndirectRef()
    {
      OpCode code = OpCodes.Stind_Ref;
      this.Generator.Emit(code);
    }
    public virtual void StoreIndirect(PrimitiveType primitiveType)
    {
      OpCode code = this.CreateNopCode();

      switch (primitiveType)
      {
        case PrimitiveType.natural_int:
          code = OpCodes.Stind_I;
          break;
        case PrimitiveType.int8:
          code = OpCodes.Stind_I1;
          break;
        case PrimitiveType.int16:
          code = OpCodes.Stind_I2;
          break;
        case PrimitiveType.int32:
          code = OpCodes.Stind_I4;
          break;
        case PrimitiveType.int64:
          code = OpCodes.Stind_I8;
          break;
        case PrimitiveType.float32:
          code = OpCodes.Stind_R4;
          break;
        case PrimitiveType.float64:
          code = OpCodes.Stind_R8;
          break;
        default:
          throw new NotSupportedException("The instruction with operand type of " + primitiveType + " is invalid!");
      }
      this.Generator.Emit(code);
    }
    public virtual void LoadIndirectRef()
    {
      OpCode code = OpCodes.Ldind_Ref;
      this.Generator.Emit(code);
    }
    public virtual void LoadIndirect(PrimitiveType primitiveType)
    {
      OpCode code = this.CreateNopCode();

      switch (primitiveType)
      {
        case PrimitiveType.natural_int:
          code = OpCodes.Ldind_I;
          break;
        case PrimitiveType.int8:
          code = OpCodes.Ldind_I1;
          break;
        case PrimitiveType.int16:
          code = OpCodes.Ldind_I2;
          break;
        case PrimitiveType.int32:
          code = OpCodes.Ldind_I4;
          break;
        case PrimitiveType.int64:
          code = OpCodes.Ldind_I8;
          break;
        case PrimitiveType.float32:
          code = OpCodes.Ldind_R4;
          break;
        case PrimitiveType.float64:
          code = OpCodes.Ldind_R8;
          break;
        case PrimitiveType.uint8:
          code = OpCodes.Ldind_U1;
          break;
        case PrimitiveType.uint16:
          code = OpCodes.Ldind_U2;
          break;
        case PrimitiveType.uint32:
          code = OpCodes.Ldind_U4;
          break;
        default:
          throw new NotSupportedException("The instruction with operand type of " + primitiveType + " is invalid!");
      }
      this.Generator.Emit(code);
    }
    #endregion
    #region Exceptions
    public virtual void ThrowException()
    {
      OpCode code = OpCodes.Throw;
      this.Generator.Emit(code);
    }
    public virtual void RethrowException()
    {
      OpCode code = OpCodes.Rethrow;
      this.Generator.Emit(code);
    }
    public virtual void LeaveException(Label label)
    {
      this.LeaveException(label, this.ShortFormat);
    }
    public virtual void LeaveException(Label label,bool shortFormat)
    {
      OpCode code = shortFormat ? OpCodes.Leave_S : OpCodes.Leave;
      this.Generator.Emit(code, label);
    }
    public virtual void EndExceptionFilter()
    {
      OpCode code = OpCodes.Endfilter;
      this.Generator.Emit(code);
    }
    public virtual void EndExceptionFinally()
    {
      OpCode code = OpCodes.Endfinally;
      this.Generator.Emit(code);
    }
    #endregion
    #region Prefix and suffix
    public virtual void InteropConvertionPrefix(CallingConvention convention)
    {
      this.interopConvertion = convention;
    }
    public virtual void ManagedConvertionPrefix(CallingConventions convertion)
    {
      this.managedConvertion = convertion;
    }

    public virtual void InteropConvertionRestore()
    {
      this.interopConvertion = CallingConvention.Winapi;
    }
    public virtual void ManagedConvertionRestore()
    {
      this.managedConvertion = CallingConventions.Standard;
    }
    public virtual void ReqParametersPrefix(params Type[] types)
    {
      this.reqParameterTypes = types;
    }
    public virtual void OptParametersPrefix(params Type[] types)
    {
      this.optParameterTypes = types;
    }
    public virtual void ReqParametersRestore()
    {
      this.reqParameterTypes = null;
    }
    public virtual void OptParametersRestore()
    {
      this.optParameterTypes = null;
    }
    public virtual void TailPrefix()
    {
      OpCode code = OpCodes.Tailcall;
      this.Generator.Emit(code);
    }
    public virtual void VolatilePrefix()
    {
      OpCode code = OpCodes.Volatile;
      this.Generator.Emit(code);
    }
    public virtual void ByteUnalignedPrefix()
    {
      OpCode code = OpCodes.Unaligned;
      this.Generator.Emit(code, (byte)1);
    }
    public virtual void ShortUnalignedPrefix()
    {
      OpCode code = OpCodes.Unaligned;
      this.Generator.Emit(code, (byte)2);
    }
    public virtual void IntUnalignedPrefix()
    {
      OpCode code = OpCodes.Unaligned;
      this.Generator.Emit(code, (byte)4);
    }
    public virtual void CheckingPrefix()
    {
      this.checking = true;
    }
    public virtual void CheckingSuffix()
    {
      this.checking = false;
    }
    public virtual void TopUnsignedPrefix()
    {
      this.topSigned = false;
    }
    public virtual void TopUnsignedSuffix()
    {
      this.topSigned = true;
    }
    public virtual void ShortFormatPrefix()
    {
      this.shortFormat = true;
    }
    public virtual void ShortFormatSuffix()
    {
      this.shortFormat = false;
    }
    #endregion
    #region Field load and store
    public virtual void StoreStaticField(FieldInfo field)
    {
      OpCode code = OpCodes.Stsfld;
      this.Generator.Emit(code, field);
    }
    public virtual void LoadStaticField(FieldInfo field)
    {
      OpCode code = OpCodes.Ldsfld;
      this.Generator.Emit(code, field);
    }
    public virtual void LoadStaticFieldAddress(FieldInfo field)
    {
      OpCode code = OpCodes.Ldsflda;
      this.Generator.Emit(code, field);
    }
    public virtual void StoreField(FieldInfo field)
    {
      OpCode code = OpCodes.Stfld;
      this.Generator.Emit(code, field);
    }
    public virtual void LoadField(FieldInfo field)
    {
      OpCode code = OpCodes.Ldfld;
      this.Generator.Emit(code, field);
    }
    public virtual void LoadFieldAddress(FieldInfo field)
    {
      OpCode code = OpCodes.Ldflda;
      this.Generator.Emit(code, field);
    }
    #endregion
    #region Object
    public virtual void CreateObjectOf(ConstructorInfo constructorInfo)
    {
      if (constructorInfo == null) throw new ArgumentNullException("constructorInfo can not be null!");
      OpCode code = OpCodes.Newobj;
      this.Generator.Emit(code, constructorInfo);
    }
    public virtual void CreateArrayOf(Type type)
    {
      if (type == null) throw new ArgumentNullException("type can not be null!");
      OpCode code = OpCodes.Newarr;
      this.Generator.Emit(code, type);
    }
    public virtual void AllocateStack()
    {
      OpCode code = OpCodes.Localloc;
      this.Generator.Emit(code);
    }
    public virtual void InitializeMemory()
    {
      OpCode code = OpCodes.Initblk;
      this.Generator.Emit(code);
    }
    public virtual void InitializeObject(Type type)
    {
      if (type == null) throw new ArgumentNullException("type can not be null!");
      OpCode code = OpCodes.Initobj;
      this.Generator.Emit(code, type);
    }
    public virtual void CopyMemory()
    {
      OpCode code = OpCodes.Cpblk;
      this.Generator.Emit(code);
    }
    public virtual void CopyObject(Type type)
    {
      if (type == null) throw new ArgumentNullException("type can not be null!");
      OpCode code = OpCodes.Cpobj;
      this.Generator.Emit(code, type);
    }
    public virtual void StoreObject(Type type)
    {
      if (type == null) throw new ArgumentNullException("type can not be null!");
      OpCode code = OpCodes.Stobj;
      this.Generator.Emit(code, type);
    }
    public virtual void LoadObject(Type type)
    {
      if (type == null) throw new ArgumentNullException("type can not be null!");
      OpCode code = OpCodes.Ldobj;
      this.Generator.Emit(code, type);
    }
    #endregion
    #region Special loading
    public virtual void LoadNull()
    {
      OpCode code = OpCodes.Ldnull;
      this.Generator.Emit(code);
    }
    public virtual void LoadString(string s)
    {
      OpCode code = OpCodes.Ldstr;
      this.Generator.Emit(code, s);
    }
    public virtual void LoadToken(MethodInfo method)
    {
      if (method == null) throw new ArgumentNullException("method can not be null!");
      OpCode code = OpCodes.Ldtoken;
      this.Generator.Emit(code, method);
    }
    public virtual void LoadToken(FieldInfo field)
    {
      if (field == null) throw new ArgumentNullException("field can not be null!");
      OpCode code = OpCodes.Ldtoken;
      this.Generator.Emit(code, field);
    }
    public virtual void LoadToken(Type type)
    {
      if (type == null) throw new ArgumentNullException("type can not be null!");
      OpCode code = OpCodes.Ldtoken;
      this.Generator.Emit(code, type);
    }
    public virtual void LoadFunction(MethodInfo method)
    {
      if (method == null) throw new ArgumentNullException("method can not be null!");
      OpCode code = OpCodes.Ldftn;
      this.Generator.Emit(code, method);
    }
    public virtual void LoadVirtualFunction(MethodInfo method)
    {
      if (method == null) throw new ArgumentNullException("method can not be null!");
      OpCode code = OpCodes.Ldvirtftn;
      this.Generator.Emit(code, method);
    }
    #endregion
    #region Ref
    public virtual void CreateRefAny(Type type)
    {
      if (type == null) throw new ArgumentNullException("type can not be null!");
      OpCode code = OpCodes.Mkrefany;
      this.Generator.Emit(code, type);
    }
    public virtual void GetRefAnyType()
    {
      OpCode code = OpCodes.Refanytype;
      this.Generator.Emit(code);
    }
    public virtual void GetRefAnyValue(Type type)
    {
      if (type == null) throw new ArgumentNullException("type can not be null!");
      OpCode code = OpCodes.Refanyval;
      this.Generator.Emit(code, type);
    }
    #endregion
    #region Stack operation
    public virtual void Idle()
    {
      OpCode code = this.CreateNopCode();
      this.Generator.Emit(code);
    }
    public virtual void Discard()
    {
      OpCode code = OpCodes.Pop;
      this.Generator.Emit(code);
    }
    public virtual void Duplicate()
    {
      OpCode code = OpCodes.Dup;
      this.Generator.Emit(code);
    }
    #endregion
    #region Utils
    protected virtual OpCode CreateNopCode()
    {
      return OpCodes.Nop;
    }
    #endregion
    #endregion
    #region Utils
    protected override void Dispose(bool disposing)
    {
      if (disposing)
      {
        this.builder = null;
        this.generator = null;
        this.reqParameterTypes = null;
        this.optParameterTypes = null;
      }
      base.Dispose(disposing);
    }
   #endregion
  }
}
